<?php
/**
 * assets.class
 * 
 * @version:	0.1
 * @package:	core
 * @author:		alex_ez
 * @created:	24 apr 2010
 *
 * @copyright:	(c) 2010 alex <qfox@ya.ru> yaroshevich aka alex_ez. All rights reserved.
 */

if( defined( '__ASSETS.CLASS_PHP' ) ) return;
define( '__ASSETS.CLASS_PHP', '0.1' );

class AssetsException extends Exception { }

class assets extends singleton
{
	// php singleton wrapper
	static public function &__getMe( ) { return parent::__getMe( __CLASS__ ); }
	static public function &instance( ) { return parent::__getMe( __CLASS__ ); }
	
	protected $config = null;
	protected $sets = array( );
	protected $version = 0;
	protected $mode = null;

	protected $js = array( );
	protected $css = array( );
	protected $printed = array( );
	
	protected $log = array( );

	protected $patterns = array(
		'js' => '<script src="%1$s" type="text/javascript"></script>',
		'css' => '<link rel="stylesheet" type="text/css" href="%1$s" />',
		);
	
	protected function __construct( )
	{
		$this ->config	= config::__getMe( );
		$this ->sets = $this ->config ->assets__sets;
		$this ->setVersion( $this ->config ->assets__version );
		$this ->setMode( $this ->config ->assets__mode );
	}
	
	public function setVersion( $version )
	{
		$this ->version = $version;
	}
	
	public function getVersion( )
	{
		return _::pick( $this ->version, 0 );
	}
	
	public function setMode( $mode )
	{
		$this ->mode = $mode;
	}
	
	public function getMode( )
	{
		return _::pick( $this ->mode, 'inline' );
	}
	
	
	/**
	 * Parsing string to array
	 * 
	 * @param string $s
	 * @return array Array with strings
	 */
	public function parseString( $s )
	{
		return array_unique(array_filter(
			explode( ' ', str_replace( ',', ' ', $s ) )
			));
	}

	public function display( )
	{
		return $this ->render( );
	}
	
	public function render( )
	{
		//var_dump( 'js:', $this ->js, 'css:', $this ->css );
		$r = '';
		
		foreach( $this ->css as $k => $v )
		{
			$r .= $this ->renderItem( 'css', $k, max( $v ) );
			unset( $this ->css[$k] );
		}
		
		foreach( $this ->js as $k => $v )
		{
			$r .= $this ->renderItem( 'js', $k, max( $v ) );
			unset( $this ->js[$k] );
		}
		
		return $r;
	}


	public function renderItem( $type, $m, $v = 0 )
	{
		$r = '';
		
		$pathtpl = 'site/%2$s/%1$s.%2$s';
		$hreftpl = $v ? sprintf('/%%2$s/%%1$s-%d.%%2$s',$v) : '/%2$s/%1$s.%2$s';
		
		// action!
		$nsis = mb_strpos( $m, '::' ) !== false;
		$ns = mb_substr( $m, 0, mb_strpos( $m, '::' ) );// namespaces have own files
		$f = str_replace( '::', '/', $m );

		//fb::log( array( $m, $ns, $f ), 'guesses' );
		$files = array( );
		foreach( array( $ns, $f ) as $guess )
		if( $guess )
		{
			$filepath = sprintf( $pathtpl, $guess, $type );
			$filehref = sprintf( $hreftpl, $guess, $type );
			$files[ $filepath ] = array( 'href' => $filehref, 'type' => $type );
		}

		foreach( $files as $path => $file )
		if( is_readable( $path ) )
		{
			if( isset( $this ->printed[$path] ) ) continue;
			$this ->printed[$path] = $v;
			
			$r .= sprintf( $this ->patterns[$type], $file['href'] )."\n";
		}
		else
			$this ->log( sprintf( '%s not found', $path ) );
		
		return $r;
	}
	
	public function fetch( )
	{
		return $this ->render( );
	}
	
	public function flush( )
	{
		echo $this ->fetch( );
	}




	/**
	 *
	 * @param <type> $type
	 * @param string $file
	 * @param numeric $version
	 */
	public function push( $type, $file, $version )
	{
		if( !isset( $this ->$type ) )
			return;
		
		$list =& $this ->$type;
		$list[$file][] = $version;
	}
	
	/**
	 * Append some data to storage (from which it placed to page)
	 *
	 * @param string $type js, css, set or image
	 * @param mixed $data list with filenames. "file1 file2", "dir::file1 file2" and so on
	 * @param numeric $version files version. 0 by default (that means only one version)
	 */
	public function append( $type, $data, $version = 0 )
	{
		if( is_string( $data ) )
			$data = $this ->parseString( $data );
		
		switch( $type )
		{
		case 'js':
			foreach( $data as $file )
			{
				$this ->push( 'js', $file, $version );
				$this ->push( 'css', $file, $version );
			}
			break;

		case 'css':
			foreach( $data as $file )
			{
				$this ->push( 'css', $file, $version );
			}
			break;
			
		case 'set':
			$sets = $data;
			foreach( $sets as $m )
			{
				$m = trim($m); if( !$m ) continue;
				if( !isset( $this ->sets[$m] ) ) { $this ->log( sprintf( 'set %s not found', $m ) ); continue; }
				
				$data = $this ->parseString( $this ->sets[$m] );
				foreach( $data as $file )
				{
					$this ->push( 'js', $file, $version );
				}
			}
			break;
			
		case 'image':
			// 
			break;
		}
	}
	
	/**
	 * Shortcut for ::append( 'js', ... )
	 */
	public function js( $data, $version = 0 )
	{
		$this ->append( 'js', $data, $version );
		return $this;
	}
	
	/**
	 * Shortcut for ::append( 'css', ... )
	 */
	public function css( $data, $version = 0 )
	{
		$this ->append( 'css', $data, $version );
		return $this;
	}

	/**
	 * Assets logger
	 * @param string $s
	 */
	protected function log( $s )
	{
		$this ->log[] = $s;
	}

	/**
	 * Assets log printer
	 */
	public function printlog( )
	{
		if( empty( $this ->log ) )
			return;
		
		fb::info( $this ->log, 'assets' );
		$this ->log = array( );
	}
	
}


?>